package rpc.remote.transport.netty.code;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import rpc.serialize.Serializer;

import java.util.List;

/**
 * @ClassName: NettyKryoDecoder
 * @Description: 自定义解码器
 * @author: Kowk
 * @since:1.0.0
 */
@AllArgsConstructor
@Slf4j
public class NettyKryoDecoder extends ByteToMessageDecoder {

    private final Serializer serializer;
    private final Class<?> genericClass;

    //Netty传输的消息，即序列化对应的字节数组的大小，存储在ByteBuf的头部
    private static final int BODY_LENGTH = 4;

    /**
     * @Description: 将序列化的字节解码
     * @Param: [channelHandlerContext 解码器关联的对象, byteBuf 传进来的字节，需要解码的ByteBuf, list 解码之后的对象需要放入集合里]
     * @return: void
     */
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        //由于写入了头部所占的字节大小为4
        if(byteBuf.readableBytes() >= BODY_LENGTH){
            //标记当前readIndex的位置，便于之后充值REadIndex的时候使用
            byteBuf.markReaderIndex();
            //读取消息长度，具体的值是Encoder的时候写入的
            int dataLen = byteBuf.readInt();
            //处理是否有不合理的情况，不合理的时候直接返回并提交日志
            if(dataLen < 0 || byteBuf.readableBytes() < 0 ){
                log.error("解码的数据长度不合法");
                return;
            }
            //继续处理不合法情况，如果可读取字节数小于消息长度，说明消息不完整，充值readIndex
            if(byteBuf.readableBytes() < dataLen){
                byteBuf.resetReaderIndex();
                return;
            }
            //异常情况处理完毕
            byte[] body = new byte[dataLen];
            //将字节写入body再将body转成相应的对象
            byteBuf.readBytes(body);
            Object obj = serializer.deserialize(body,genericClass);
            list.add(obj);
            log.info("成功解码字节流");
        }
    }
}
